#include "queue.h"
#include <iostream>
#include <tuple>

using namespace std;

template <typename T>
Queue<T>::Queue(int capacity)
{
    this->cap = capacity;
    this->len = 0;
    this->head = new Node<T>{T(), nullptr, nullptr};
    this->tail = new Node<T>{T(), nullptr, nullptr};
    this->head->next = this->tail;
    this->tail->prev = this->head;
};

template <typename T>
void Queue<T>::Clear()
{
    this->len = 0;
    for (Node<T> *node = this->head->next; node!= this->tail; node = node->next){
        delete node;
    }
    this->head->next = this->tail;
    this->tail->prev = this->head;
}

template <typename T>
bool Queue<T>::IsEmpty() const
{
    return this->len == 0;
}

template <typename T>
bool Queue<T>::IsFull() const
{
    return this->len == this->cap;
}

template <typename T>
int Queue<T>::Len() const
{
    return this->len;
}

template <typename T>
bool Queue<T>::EnQueue(T element)
{
    if (this->IsFull())
    {
        return false;
    }
    Node<T> *node = new Node<T>{element, nullptr, nullptr};
    Node<T> *prev = this->tail->prev;
    node->prev = prev;
    prev->next = node;
    node->next = this->tail;
    this->tail->prev = node;
    this->len++;
    return true;
}

template <typename T>
tuple<bool, T> Queue<T>::DeQueue()
{
    if (this->IsEmpty())
    {
        return make_tuple(false, T());
    }
    Node<T> *node = this->head->next;
    T element = node->element;
    Node<T> *next = node->next;
    next->prev = this->head;
    this->head->next = next;
    delete node;
    this->len--;
    return make_tuple(true, element);
}

int main()
{
    Queue<int> *q = new Queue<int>(5);
    cout << "Queue Empty: " << (q->IsEmpty() ? "true" : "false") << endl;
    for (int i = 0; i < 5; i++)
    {
        bool success = q->EnQueue(i);
        cout << "Enqueued element: " << i << " Success: " << (success ? "true" : "false") << endl;
    }
    cout << "Queue Full: " << (q->IsFull() ? "true" : "false") << endl;
    for (int i = 0; i < 5; i++)
    {
        bool success;
        int element;
        tie(success, element) = q->DeQueue();
        cout << "Dequeued success: " << (success ? "true" : "false") << " element: " << element << endl;
    }
    for (int i = 0; i < 5; i++)
    {
        q->EnQueue(i);
    }
    cout << "Queue Length: " << q->Len() << endl;
    q->Clear();
    cout << "Queue Empty: " << (q->IsEmpty() ? "true" : "false") << endl;
    delete q;
    return 0;
}
